﻿namespace ComTools.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Web.Routing;

    public class EntityHelper
    {
        /// <summary>将实体转换成键/值对的集体</summary>
        /// <param name="entityObject">对象</param>
        /// <returns>处理结果</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static IDictionary<string, object> ToDictionary(object entityObject)
        {
            return new RouteValueDictionary(entityObject);
        }

        /// <summary>将键值对转称成Model</summary>
        /// <typeparam name="TResult">输出模型类型</typeparam>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="dictionary"></param>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static TResult ToModel<TResult, TKey, TValue>(IDictionary<TKey, TValue> dictionary)
        {
            // 创建返回结果实例
            TResult instance = (TResult)Activator.CreateInstance(typeof(TResult));
            // 获取结果的所有属性
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(instance);
            // 遍历键值对
            foreach (TKey key in dictionary.Keys)
            {
                PropertyDescriptor propertyDescriptor = properties.Find(Convert.ToString(key), true);
                if (propertyDescriptor != null && !propertyDescriptor.IsReadOnly)
                {
                    bool flag1 = propertyDescriptor.PropertyType.IsAssignableFrom(propertyDescriptor.PropertyType);
                    bool flag2 = !flag1 && Nullable.GetUnderlyingType(propertyDescriptor.PropertyType) == propertyDescriptor.PropertyType;
                    if (flag1 || flag2)
                    {
                        TValue obj = dictionary[key];
                        if (flag1 || obj != null && flag2)
                            propertyDescriptor.SetValue(instance, obj);
                    }
                }
            }
            return instance;
        }

        /// <summary>克隆实体对象</summary>
        /// <param name="entityObject">实体对象</param>
        /// <returns>处理结果</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static object Clone(object entityObject)
        {
            if (entityObject == null)
                return (object)null;
            var instance = Activator.CreateInstance(entityObject.GetType());
            var properties1 = TypeDescriptor.GetProperties(entityObject);
            var properties2 = TypeDescriptor.GetProperties(instance);
            foreach (PropertyDescriptor propertyDescriptor1 in properties1)
            {
                var propertyDescriptor2 = properties2.Find(propertyDescriptor1.Name, true);
                if (propertyDescriptor2 == null || propertyDescriptor2.IsReadOnly) continue;
                bool flag1 = propertyDescriptor2.PropertyType.IsAssignableFrom(propertyDescriptor1.PropertyType);
                bool flag2 = !flag1 && Nullable.GetUnderlyingType(propertyDescriptor1.PropertyType) == propertyDescriptor2.PropertyType;
                if (!flag1 && !flag2) continue;
                object obj = propertyDescriptor1.GetValue(entityObject);
                if (flag1 || obj != null && flag2)
                    propertyDescriptor2.SetValue(instance, obj);
            }
            return instance;
        }

        /// <summary>克隆实体对象</summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="entityObject">实体对象</param>
        /// <returns>处理结果</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static T Clone<T>(object entityObject)
        {
            if (entityObject == null)
                return default(T);
            T instance = (T)Activator.CreateInstance(typeof(T));
            PropertyDescriptorCollection properties1 = TypeDescriptor.GetProperties(entityObject);
            PropertyDescriptorCollection properties2 = TypeDescriptor.GetProperties((object)instance);
            foreach (PropertyDescriptor propertyDescriptor1 in properties1)
            {
                PropertyDescriptor propertyDescriptor2 = properties2.Find(propertyDescriptor1.Name, true);
                if (propertyDescriptor2 != null && !propertyDescriptor2.IsReadOnly)
                {
                    bool flag1 = propertyDescriptor2.PropertyType.IsAssignableFrom(propertyDescriptor1.PropertyType);
                    bool flag2 = !flag1 && Nullable.GetUnderlyingType(propertyDescriptor1.PropertyType) == propertyDescriptor2.PropertyType;
                    if (flag1 || flag2)
                    {
                        object obj = propertyDescriptor1.GetValue(entityObject);
                        if (flag1 || obj != null && flag2)
                            propertyDescriptor2.SetValue((object)instance, obj);
                    }
                }
            }
            return instance;
        }
    }
}
